/*
 * set_PS.c
 *
 *  Created on: Jan 17, 2014
 *      Author: Rohit
 * This file contains the functions used to set the condition flags (N, Z, C, V).
 * These are a part of the PS (program status) register
 *
 */
//INCLUDES
#include "includes.h"

/*Function: 	set_N_flag
 *Description: 	This function sets the N (negative) flag in the PS register.
*/
void set_N_flag(void)
{
	//MemSpace[PS] |= 0x0008;					//Set the N flag in the PS register
	write_in_memory(PS,(read_from_memory(PS,DATA) | 0x0008), DATA);
}

/*Function: 	clear_N_flag
 *Description: 	This function clears the N (negative) flag in the PS register.
*/
void clear_N_flag(void)
{
	//MemSpace[PS] &= 0x1117;					//Clear the N flag in the PS register
	write_in_memory(PS,(read_from_memory(PS,DATA) & 0x1117), DATA);
}

/*Function: 	set_Z_flag
 *Description: 	This function sets the Z (zero) flag in the PS register.
*/
void set_Z_flag(void)
{
	//MemSpace[PS] |= 0x0004;					//Set the Z flag in the PS register
	write_in_memory(PS,(read_from_memory(PS,DATA) | 0x0004), DATA);
}

/*Function: 	clear_Z_flag
 *Description: 	This function clears the Z (zero) flag in the PS register.
*/
void clear_Z_flag(void)
{
	//MemSpace[PS] &= 0x111B;					//Clear the Z flag in the PS register
	write_in_memory(PS,(read_from_memory(PS,DATA) & 0x111B), DATA);
}

/*Function: 	set_V_flag
 *Description: 	This function sets the V (overflow) flag in the PS register.
*/
void set_V_flag(void)
{
	//MemSpace[PS] |= 0x0002;					//Set the V flag in the PS register
	write_in_memory(PS,(read_from_memory(PS,DATA) | 0x0002), DATA);
}

/*Function: 	clear_V_flag
 *Description: 	This function clears the V (overflow) flag in the PS register.
*/
void clear_V_flag(void)
{
	//MemSpace[PS] &= 0x111D;					//Clear the V flag in the PS register
	write_in_memory(PS,(read_from_memory(PS,DATA) & 0x111D), DATA);
}

/*Function: 	set_C_flag
 *Description: 	This function sets the C (carry) flag in the PS register.
*/
void set_C_flag(void)
{
	//MemSpace[PS] |= 0x0001;					//Set the C flag in the PS register
	write_in_memory(PS,(read_from_memory(PS,DATA) | 0x0001), DATA);
}

/*Function: 	clear_C_flag
 *Description: 	This function clears the C (carry) flag in the PS register.
*/
void clear_C_flag(void)
{
	//MemSpace[PS] &= 0x111E;					//Clear the C flag in the PS register
	write_in_memory(PS,(read_from_memory(PS,DATA) & 0x111E), DATA);
}


/*Function: 	update_Z_flag
 *Description: 	This function updates the Z (zero) flag in the PS register if the value of the data is equal to 0.
*/

void update_Z_flag(unsigned short data)
{
	if(data == 0)
		set_Z_flag();
	else
		clear_Z_flag();
}

/*Function: 	update_N_flag
 *Description: 	This function updates the N (negative) flag in the PS register if the value of the data is less than 0.
*/

void update_N_flag(int mnemonic, unsigned short data)
{
	switch(mnemonic){

		case BIS:
		case BIC:
		case BIT:
		case ADD:
		case SUB:
		case COM:
		case ADC:
		case ROR:
		case ROL:
		case ASR:
		case ASL:
		case SBC:
		case TST:
		case NEG:
		case DEC:
		case INC:
			if(data & 0x8000)
				set_N_flag();
			else
				clear_N_flag();
			break;

		case SWAB:
			if(data & 0x0080)
				set_N_flag();
			else
				clear_N_flag();
			break;

		case CLR:
			clear_N_flag();
			break;

		default:
			if(data & 0x8000)
				set_N_flag();
			else
				clear_N_flag();
			break;
	}
}

/*Function: 	update_V_flag
 *Description: 	This function updates the V (overflow) flag in the PS register.
 	 	 	 	 Addition/Subtraction of two operands with different sign bit never generates an overflow.
*/

void update_V_flag(int mnemonic,unsigned short operand_source, unsigned short operand_destination, unsigned short result)
{
	switch(mnemonic)
	{
		case ADD:
			if((operand_source & 0x8000)-(operand_destination & 0x8000) == 0) 	// two operands with same sign
				if((result & 0x8000)-(operand_source & 0x8000) != 0) 	// result has opposite sign
					set_V_flag();
				else
					clear_V_flag();
			else
				clear_V_flag();
			break;

		case SUB:
			if((operand_source & 0x8000)-(operand_destination & 0x8000) != 0) 	// two operands with different sign
				if((result & 0x8000)-(operand_source & 0x8000) == 0) 	// result has the same sign as source
					set_V_flag();
				else
					clear_V_flag();
			else
				clear_V_flag();
			break;

		case CMP:
			if((operand_source & 0x8000)-(operand_destination & 0x8000) != 0) 	// two operands with different sign
				if((result & 0x8000)-(operand_destination & 0x8000) == 0) 	// result has the same sign as destination
					set_V_flag();
				else
					clear_V_flag();
			else
				clear_V_flag();
			break;

		case BIS:
		case MOV:
		case BIC:
		case BIT:
		case CLR:
		case TST:
		case COM:
		case SWAB:
			clear_V_flag();
			break;

		case INC:
			if(operand_source == 32767)
				set_V_flag();
			else
				clear_V_flag();
			break;

		case NEG:
			if(result == 32768)
				set_V_flag();
			else
				clear_V_flag();
			break;

		case SBC:
			if(result == 32768)
				set_V_flag();
			else
				clear_V_flag();
			break;
	}
}


/*Function: 	update_C_flag
 *Description: 	This function updates the C (carry) flag in the PS register.
 	 	 	 	Carry flag is set when any operation results exceeds the 16-bit limit.
*/

void update_C_flag(int mnemonic,unsigned short operand_source, unsigned short operand_destination, unsigned short result, int result_32_bit)
{

	switch(mnemonic)
	{

		case ADD:
			if(result_32_bit > 65535)
				set_C_flag();
			else
				clear_C_flag();
			break;

		case SUB:
			if(result_32_bit > 65535)
				clear_C_flag();
			else
				set_C_flag();
			break;

		case CMP:
			if((operand_source > operand_destination)?(result < operand_destination):(result < operand_source)) 	// comparing result with minimum of two operands
				clear_C_flag();
			else
				set_C_flag();
			break;

		case CLR:
		case TST:
		case SWAB:
			clear_C_flag();
			break;

		case COM:
			set_C_flag();
			break;

		case DEC:
			if(operand_source == 32768)
				set_C_flag();
			else
				clear_C_flag();
			break;

		case NEG:
			if(result == 0)
				clear_C_flag();
			else
				set_C_flag();
			break;
	}
}

/*Function: 	get_N_flag
 *Description: 	This function reads the N (negative) flag in the PS register.
*/
unsigned short get_N_flag(void)
{
	return ((read_from_memory(PS,DATA) >> 3) & 0x0001);
}

/*Function: 	get_Z_flag
 *Description: 	This function reads the Z (zero) flag in the PS register.
*/
unsigned short get_Z_flag(void)
{
	return ((read_from_memory(PS,DATA) >> 2) & 0x0001);
}

/*Function: 	get_V_flag
 *Description: 	This function reads the V (overflow) flag in the PS register.
*/
unsigned short get_V_flag(void)
{
	return ((read_from_memory(PS,DATA) >> 1) & 0x0001);
}

/*Function: 	get_C_flag
 *Description: 	This function reads the C (carry) flag in the PS register.
*/
unsigned short get_C_flag(void)
{
	return (read_from_memory(PS,DATA) & 0x0001);
}
